package com.sann.spring.proxy;

import com.sann.spring.service.IAccountService;
import com.sann.spring.util.TransactionManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 用于创建Service的代理对象的工厂。
 * 代理 Service 层的Bean 工厂。将Service层的事务控制代码由代理类提供。
 */
@Component
//@Configuration//标注为配置类还不行，报txManager注入不了- 没有 TransactionManager 类型的Bean,这只是IDEA自身问题，程序能正常运行
public class BeanFactoryProxy {

    /**
     * 给工厂注入被代理的对象(工厂拿到被代理对象，用于产生代理对象).
     */
    @Autowired
    IAccountService accountService ;

    @Autowired
    TransactionManager txManager;


    /**
     * 定义一个工厂方法，用于生产被代理对象（添加事务增强逻辑的对象）
     *
     * 这个注解一添加，整个IOC容器中就有两个IAccountService类型的Bean，Bean名分别是双引号中名称：
     * @Bean(name="proxyIAccountService") 和  @Service(value="accountService")
     *
     * @return 返回值就是Bean的类型
     */
    @Bean(name="proxyIAccountService")
    public IAccountService getAccountServiceProxy() {
        IAccountService proxyIAccountService = (IAccountService)Proxy.newProxyInstance(
                accountService.getClass().getClassLoader(),
                accountService.getClass().getInterfaces(),
                new InvocationHandler() {
                    /**
                     * 添加事务支持
                     */
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        Object rtValue = null;
                        try {
                            //1.开启事务
                            txManager.beginTransaction();
                            //2.执行操作
                            rtValue = method.invoke(accountService, args);
                            //3.提交事务
                            txManager.commit();
                            //4.返回结果
                            return rtValue;
                        }catch (Exception e){
                            e.printStackTrace();
                            //5.回滚事务
                            txManager.rollback();
                            // 注意，有返回值的方法，catch 中必须抛异常结束程序运行
                            throw new RuntimeException(e);
                        }finally {
                            //6.释放连接
                            txManager.release();
                        }
                    }
                });
        return proxyIAccountService;
    }

}
